# write by hasaki
# first edit on 2019/04/15
# last change on 2019/07/29
# 合成其他bar线的功能类
import json
from datetime import datetime,timedelta
import time

from hashakisea.strategy.haStrategyTemplate import HaStrategy

class UpdateBar(HaStrategy):
    def __init__(self):     
        super(UpdateBar,self).__init__()
        self.strategy_name='update bar'
        self.hour_bar_list=[]                 # 小时线数据保存列表
        self.bar_list=[]                      # 小时线内的数据保存列表
        self.last_time_4h=None                # 4小时K线上一次更新的时间
        self.last_time_1h=None                # 1小时K线上一次更新时间
        self.is_update=False                  # 是否到了更新数据的时候
        self.is_update_1hour=False            # 是否到了更新数据的时候
        self.counter_of_hour_bar=0            # 小时线的个数
        self.counter_of_bar=0                 # 小时线内的K线个数

        self.bar_of_4h=None                   # 最新4小时的K线
        self.bar_of_1h=None                   # 最新1小时的K线
        self.today_1h_bar_list=[]             # type:list 保存最重要持久化的1小时K线列表
        self.save_json_path='C:/Users/cchyp/Desktop/hasaki/quote/last_week/2019-7-7.json'
        self.save_json_ALL='C:/Users/cchyp/Desktop/hasaki/quote/last_week/2019.json'   # 按年来保存

        self.read1hFileFirst=True             # 是否是第一次获取1小时历史数据句柄
    
    # ------------------------------------------------------------------------------------------------
    # 另外加的大周期处理逻辑
    def onBar_4h(self,data):
        '''4小时周期的onBar'''
        print('获取到4小时周期的K线',data)
        # 读取
        with open(self.save_json_path,'r',encoding='utf-8') as json_file:
            json_data=json.load(json_file)

        # 判断最新的时间是否至少大于上一根K线时间3个半小时
        if json_data:
            temp_last = datetime.strptime(json_data[-1]['time'],'%Y-%m-%d %H:%M:%S')
            temp_new = datetime.strptime(data['time'],'%Y-%m-%d %H:%M:%S')
            if temp_last+timedelta(hours=3)>temp_new:
                # 新的时间不够
                print('时间差不足以保存4小时K线')
                return
        else:
            print('原始文件为空,直接保存4小时K线')

        # 更新数据
        json_data.append(data)

        # 写入,indent=4这个参数会格式化保存的json，自动换行吧，这么理解
        with open(self.save_json_path,'w',encoding='utf-8') as json_file:
            json.dump(json_data,json_file,ensure_ascii=False,indent=4)

    # ------------------------------------------------------------------------------------------------
    # 把历史行情保存一个文件里面
    def saveHistory1hour(self,data):
        '''把4小时K线历史行情数据保存到一个文件里面'''
        if self.read1hFileFirst:
            # 读取
            with open(self.save_json_ALL,'r',encoding='utf-8') as json_file:
                self.today_1h_bar_list=json.load(json_file)
            
            # 已经读取了1小时K线的历史数据，设置开关
            self.read1hFileFirst=False
            
        # 判断最新的时间是否至少大于上一根K线时间半小时
        if self.today_1h_bar_list:
            temp_last = datetime.strptime(self.today_1h_bar_list[-1]['time'],'%Y-%m-%d %H:%M:%S')
            temp_new = datetime.strptime(data['time'],'%Y-%m-%d %H:%M:%S')
            if temp_last+timedelta(hours=0.5)>temp_new:
                # 新的时间不够
                print('保存1小时K线的时间不够')
                return
        else:
            print('原始文件为空,直接保存1小时K线')
        
        # 更新数据
        self.today_1h_bar_list.append(data)

    # ------------------------------------------------------------------------------------------------
    def next(self,data):
        '''data={'time': '2019-04-15 15:36:00', 'close': '5.542', 'high': '5.542', 'low': '5.542', 'open': '5.542', 'name': '1m'} 
        引擎会推送一分钟的数据也会推送一小时的数据，不需要从一分钟合成一小时的数据，有现成的数据接口'''
        #return
        if not self.bar_of_4h:
            self.historyMake4hourBar()
            print('从历史行情生成4小时K线')
        
        if 'last' not in data:
            # 收到的不是tick数据
            self.onBar(data)
        else:
            self.onTick(data)
    
    def onBar(self,data):
        '''接收bar信息'''
        self.transerTime(data)

        if data['name']=='1m':
            pass
        elif data['name']=='1h':
            self.update_1h_bar(data)
            self.update_4h_bar(data)
        else:
            print('既不是一分钟数据也不是一小时数据，说明传进来的数据有问题，传进来的K线数据是：',data)
    
    def onTick(self,data):
        pass
    
    def onOrder(self):
        pass
    
    def onTrade(self):
        pass
    
    def update_5min_bar(self,bar):
        '''合成5分钟的K线'''
        pass
    
    def update_1h_bar(self,bar):
        '''合成小时线'''
        self.counter_of_bar+=1

        self.bar_list.append(bar)
        big_bar={}
        # 更新成更大周期的K线
        if self.is_update_1hour:
            big_bar['time']=bar['time']
            big_bar['open']=self.bar_list[0]['open']
            big_bar['close']=bar['close']
            big_bar['high']=max([i['high'] for i in self.bar_list])
            big_bar['low']=min([j['low'] for j in self.bar_list])

            # 先求所有成交量的总和再除以小时线的条数，即求出平均一小时的成交量，得出1小时的平均成交量
            big_bar['volume']= sum([k['volume'] for k in self.bar_list]) / self.counter_of_bar

            self.bar_of_1h=big_bar
            self.saveHistory1hour(self.bar_of_1h)

            # 合成好了大周期的K线后接下来就是收尾工作
            self.is_update_1hour=False
            self.counter_of_bar=0
            self.bar_list.clear()
    
    def update_4h_bar(self,bar):
        '''生成4小时的线'''
        self.counter_of_hour_bar+=1

        self.hour_bar_list.append(bar)
        big_bar={}
        # 更新成更大周期的K线
        if self.is_update:
            big_bar['time']=bar['time']
            big_bar['open']=self.hour_bar_list[0]['open']
            big_bar['close']=bar['close']
            big_bar['high']=max([i['high'] for i in self.hour_bar_list])
            big_bar['low']=min([j['low'] for j in self.hour_bar_list])

            # 先求所有成交量的总和再除以小时线的条数，即求出平均一小时的成交量，最后乘以4，得出4小时的平均成交量
            big_bar['volume']= 4 * sum([k['volume'] for k in self.hour_bar_list]) / self.counter_of_hour_bar

            self.bar_of_4h=big_bar
            self.onBar_4h(self.bar_of_4h)

            # 合成好了大周期的K线后接下来就是收尾工作
            self.is_update=False
            self.counter_of_hour_bar=0
            self.hour_bar_list.clear()
        
    def transerTime(self,data):
        '''时间大小比较'''
        if not self.last_time_4h:
            self.last_time_4h=datetime.strptime(data['time'],'%Y-%m-%d %H:%M:%S')
        
        if not self.last_time_1h:
            self.last_time_1h=datetime.strptime(data['time'],'%Y-%m-%d %H:%M:%S')

        if self.last_time_4h+timedelta(hours=4)<=datetime.strptime(data['time'],'%Y-%m-%d %H:%M:%S'):
            print('更新4小时K线',data['time'])
            self.last_time_4h=datetime.strptime(data['time'],'%Y-%m-%d %H:%M:%S')
            self.is_update=True
                    
        if self.last_time_1h+timedelta(hours=1)<=datetime.strptime(data['time'],'%Y-%m-%d %H:%M:%S'):
            print('更新1小时K线',data['time'])
            self.last_time_1h=datetime.strptime(data['time'],'%Y-%m-%d %H:%M:%S')
            self.is_update_1hour=True

    def historyMake4hourBar(self):
        '''根据从交易所获取到的历史一分钟K线来合成需要的周期K线'''
        for i in self.history_bars['eos_usdt']:
            try:
                form_time=int(i['time'])/1000
            except ValueError as error:
                print('出现了value error,这个错误为',error,'错误的时间：',i['time'])
                continue
            i['time']=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(form_time))
            self.transerTime(i)
            self.update_4h_bar(i)
            self.update_1h_bar(i)
        
        # 因为保存1小时K线的数据读写次数和1小时的数据比较多，所以这里改成，先把所有的1小时K线数据保存在内存
        # 最后运行完之后再一次性保存到硬盘
        with open(self.save_json_ALL,'w',encoding='utf-8') as json_file:
            json.dump(self.today_1h_bar_list,json_file,ensure_ascii=False,indent=4)